package com.labofjet.system.service.impl;

import com.github.pagehelper.PageInfo;
import com.labofjet.common.dto.ContextDto;
import com.labofjet.common.util.JSONUtils;
import com.labofjet.common.util.ListHelpers;
import com.labofjet.system.annotation.RedisCacheEvicat;
import com.labofjet.system.constant.CRedisCacheConstant;
import com.labofjet.system.dto.*;
import com.labofjet.system.enums.EState;
import com.labofjet.system.mapper.SysUserMapper;
import com.labofjet.system.mapper.SysUserRoleMapper;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SysUserServiceImpl extends CrudBaseServiceImpl<SysUserDto> {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private SysRoleServiceImpl sysRoleService;

    @Autowired
    private SysPermissionServiceImpl sysPermissionService;

    @Override
    @Cacheable(value = CRedisCacheConstant.USER_PAGE_PREFIX, key = CRedisCacheConstant.CACHE_PAGE)
    public PageInfo<SysUserDto> list(ContextDto result) {
        Map<String, Object> map = super.prepare(result);
        List<SysUserDto> sysMenuDtos = sysUserMapper.selectList(map);
        return new PageInfo<>(sysMenuDtos);
    }

    @Override
    @Cacheable(value = CRedisCacheConstant.USER_ID_PREFIX, key = CRedisCacheConstant.CACHE_ID)
    public SysUserDto load(ContextDto result) {
        Map<String, Object> map = super.getRequestParamsMap(result);
        Integer id = (Integer) map.get("id");
        if (null != id) {
            SysUserDto sysUserDto = sysUserMapper.selectList(map).get(0);
            return sysUserDto;
        }
        return null;
    }

    @Override
    @Transactional
    @Caching(evict = {
            @CacheEvict(value = CRedisCacheConstant.USER_ID_PREFIX, key = CRedisCacheConstant.CACHE_EVICT_ID)
    })
    @RedisCacheEvicat(evict = @CacheEvict(value = CRedisCacheConstant.USER_PAGE_PREFIX, allEntries = true))
    public SysUserDto save(ContextDto result) {
        SysUserDto dto = JSONUtils.getRequestData(result, SysUserDto.class);
        if (dto.getId() != null) {
            sysUserMapper.updateByPrimaryKey(dto);
        } else {
            sysUserMapper.insertSelective(dto);
        }
        this.saveUserRole(dto);
        sysRoleService.evictPageCache();
        return dto;
    }

    @Override
    @Transactional
    @RedisCacheEvicat(evict = {@CacheEvict(value = CRedisCacheConstant.USER_PAGE_PREFIX, allEntries = true),
            @CacheEvict(value = CRedisCacheConstant.USER_ID_PREFIX)})
    public int delete(ContextDto result) {
        List<Integer> ids = JSONUtils.getRequestData(result, List.class);
        SysUserExample example = new SysUserExample();
        example.createCriteria().andIdIn(ids);
        int i = sysUserMapper.deleteByExample(example);
        return i;
    }

    /**
     * 保存用户关联的角色
     * @param dto
     */
    private void saveUserRole(SysUserDto dto) {
        List<Integer> ids = dto.getSysRoleIdList();
        if (CollectionUtils.isNotEmpty(ids)) {
            SysUserRoleExample example = new SysUserRoleExample();
            example.createCriteria().andRoleIdNotIn(ids).andUserIdEqualTo(dto.getId());
            sysUserRoleMapper.deleteByExample(example);
            sysUserRoleMapper.insertByUser(dto);
        } else {
            SysUserRoleExample example = new SysUserRoleExample();
            example.createCriteria().andUserIdEqualTo(dto.getId());
            sysUserRoleMapper.deleteByExample(example);
        }
    }

    public SysUserDto findByUsername(SysUserDto sysUserDto) {
        String username = sysUserDto.getUsername();
        if (StringUtils.isEmpty(username)) {
            return null;
        }
        SysUserExample example = new SysUserExample();
        example.createCriteria().andUsernameEqualTo(username);
        List<SysUserDto> sysUserDtos = sysUserMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(sysUserDtos)) {
            return null;
        }
        return sysUserDtos.get(0);
    }

    /**
     * 为用户加载权限和角色
     *
     * @param sysUserDto
     */
    public void loadPermissionsAndRoles(SysUserDto sysUserDto) {
        // role
        Map<String, Object> m = new HashMap<>();
        m.put("userId", sysUserDto.getId());
        m.put("state", EState.VALID.getCode());
        ContextDto contextDto = new ContextDto();
        contextDto.setRequestParams(m);
        List<SysRoleDto> roleDtos = sysRoleService.list(contextDto).getList();
        sysUserDto.setSysRoleDtoList(roleDtos);
        if (CollectionUtils.isEmpty(roleDtos)) { // 没有权限
            sysUserDto.setSysRoleDtoList(new ArrayList<>());
            sysUserDto.setSysPermissionDtos(new ArrayList<>());
            sysUserDto.setSysRoleIdList(new ArrayList<>());
            return;
        }
        ArrayList<Integer> roleIds = new ArrayList<>();
        for (SysRoleDto roleDto : roleDtos) {
            roleIds.add(roleDto.getId());
        }
        sysUserDto.setSysRoleIdList(roleIds);

        // permission
        List<SysPermissionDto> permissionDtos = new ArrayList<>();
        for (SysRoleDto roleDto : roleDtos) {
            Map<String, Object> map = new HashMap<>();
            map.put("roleId", roleDto.getId());
            contextDto.setRequestParams(map);
            List<SysPermissionDto> sysPermissionDtos = sysPermissionService.list(contextDto).getList();
            if (CollectionUtils.isNotEmpty(roleDtos)) {
                permissionDtos.addAll(sysPermissionDtos);
            }
        }
        sysUserDto.setSysPermissionDtos(permissionDtos);

    }

    /**
     * 通过role查找关联的用户
     *
     * @param sysRoleDto
     * @return
     */
    public List<SysUserDto> findByRole(SysRoleDto sysRoleDto) {
        List<SysRoleDto> roleDtos = sysRoleService.find(sysRoleDto);
        if (CollectionUtils.isEmpty(roleDtos)) {
            return new ArrayList<>();
        }
        sysRoleDto = roleDtos.get(0);

        SysUserRoleExample example = new SysUserRoleExample();
        example.createCriteria().andRoleIdEqualTo(sysRoleDto.getId());
        List<SysUserRoleDto> sysUserRoleDtos = sysUserRoleMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(sysUserRoleDtos)) {
            List<Integer> userIds = new ArrayList<>();
            for (SysUserRoleDto sysUserRoleDto : sysUserRoleDtos) {
                userIds.add(sysUserRoleDto.getUserId());

            }
            SysUserExample sysUserExample = new SysUserExample();
            sysUserExample.createCriteria().andIdIn(userIds);
            return sysUserMapper.selectByExample(sysUserExample);
        }

        return new ArrayList<>();
    }

    /**
     * 给用户设置role
     *
     * @param sysUserDtos
     */
    public void assembleRoleForUsers(List<SysUserDto> sysUserDtos) {
        if (CollectionUtils.isEmpty(sysUserDtos)) { // 如果参数为空
            return;
        }

        List<Integer> userIds = new ArrayList<>();
        for (SysUserDto sysUserDto : sysUserDtos) { // 取出所有用户ID一次查找对应的角色
            userIds.add(sysUserDto.getId());
        }
        Map<String, Object> params = new HashMap<>();
        params.put("userIds", userIds);
        List<SysUserRoleDto> sysUserRoleDtos = sysUserRoleMapper.selectList(params);
        if (CollectionUtils.isEmpty(sysUserRoleDtos)) {
            return;
        }
        ListHelpers.combineList(sysUserDtos, sysUserRoleDtos, new ListHelpers.Match<SysUserDto, SysUserRoleDto>() {
            @Override
            public boolean beforeMatch(SysUserDto sysUserDto) {
                if (CollectionUtils.isEmpty(sysUserDto.getSysRoleDtoList())) {
                    sysUserDto.setSysRoleDtoList(new ArrayList<>());
                }
                return true;
            }

            @Override
            public void whenMatch(SysUserDto sysUserDto, SysUserRoleDto sysUserRoleDto) {
                SysRoleDto sysRoleDto = new SysRoleDto(); // 这里也可以用ConverterUtils去转化.比较简单,所以我就直接new了
                sysRoleDto.setText(sysUserRoleDto.getRoleName());
                sysUserDto.getSysRoleDtoList().add(sysRoleDto);
            }

            @Override
            public boolean match(SysUserDto sysUserDto, SysUserRoleDto sysUserRoleDto) {
                return sysUserDto.getId().equals(sysUserRoleDto.getUserId());
            }
        });

    }

    public List<SysUserDto> selectByExample(SysUserExample sysUserExample) {
        return sysUserMapper.selectByExample(sysUserExample);
    }
}
